import pandas as pd
from _01A通用绘图生成分析 import load_plot_and_chat_data
import re
from pptx.oxml.ns import qn
from pptx import Presentation
from pptx.util import Inches, Pt, Cm
from pptx.enum.shapes import MSO_SHAPE
from pptx.dml.color import RGBColor


def get_content_in_minus(text):
    pattern = r'#(.*?)#'  # 匹配括号内的任意字符
    matches = re.findall(pattern, text)
    result=''
    return result.join(matches)


def remove_minus(text):
    pattern = r"\#[^()]*\#"
    return re.sub(pattern, "", text)


def set_font_properties(run, font_name, font_size, color_rgb, bold=False):
    run.font.name = font_name
    run.font.size = font_size
    run.font.bold = bold
    run.font.color.rgb = color_rgb

    try:
        if hasattr(run.font, '_element') and run.font._element is not None:
            rPr = run.font._element.get_or_add_rPr()
            rPr.set(qn('w:eastAsia'), font_name)
        elif hasattr(run, '_element') and run._element is not None:
            rPr = run._element.get_or_add_rPr()
            rPr.set(qn('w:eastAsia'), font_name)
    except (AttributeError, Exception):
        pass
    

# 调用 load_plot_and_chat_data 函数加载图像、聊天文本和数据，不保存缓存
all_data = load_plot_and_chat_data(load_cache=True, save_cache=True, chat=True)
# 从加载的数据中提取图像路径字典
img_paths = all_data['img_collection']
# 从加载的数据中提取聊天文本字典
chats = all_data['chat_collection']
# 从加载的数据中提取数据字典
datas = all_data['data_collection']

# 创建一个新的 PowerPoint 演示文稿对象
prs = Presentation()
# 设置演示文稿幻灯片的宽度为 13.33 英寸
prs.slide_width = Inches(13.33)
# 设置演示文稿幻灯片的高度为 7.5 英寸
prs.slide_height = Inches(7.5)

# 读取包含绘图参数的 Excel 文件，将所有工作表读取为字典
plot_excel = pd.read_excel(
    'meta\plot_args_use.xlsx', 
    sheet_name=None,
    index_col=0,
    )

# 获取 Excel 文件中 'plot_data' 工作表的数据
plot_info = plot_excel['plot_data']
# 将 'save_name' 列设置为索引
plot_info.index = plot_info['save_name']

# 按 'ppt' 列对数据进行分组，遍历每个分组
for ppt_page, plot_df in plot_info.groupby('ppt'):
    # 在演示文稿中添加一张新幻灯片，使用空白幻灯片布局
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    # 初始化标题文本
    header = ''
    # 用于控制标题添加次数的计数器
    header_text = 0
    # 标记是否为第一张图片
    first_img = False
    # 标记是否为第一段文本
    first_text = False

    # 遍历分组内的每一行数据
    for save_name, se in plot_df.iterrows():
        # 获取当前行的主题
        theme = se['theme']
        # 在幻灯片上添加一个矩形形状
        shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Cm(0), Cm(0.8), Cm(0.5), Cm(1.8))
        # 设置矩形的填充样式为纯色
        shape.fill.solid()
        # 设置矩形的填充颜色为 RGB(188, 54, 73)
        shape.fill.fore_color.rgb = RGBColor(188, 54, 73)

        # 获取当前主题和保存名称对应的图像路径列表
        img_paths_li = img_paths[theme][save_name]
        print(f"Page", save_name)

        # 根据是否为第一张图片设置图片的左侧位置
        if first_img:
            left = Cm(1)
        else:
            left = Cm(18)
        # 设置图片的顶部位置
        top = Cm(8.5)
        # 设置图片的宽度
        width = Cm(15)

        # 在幻灯片上添加图片
        pic = slide.shapes.add_picture(img_paths_li[0], left=left, top=top, width=width)

        # 设置文本框的左侧位置
        text_left = Cm(1)
        # 设置文本框的顶部位置
        text_top = Cm(1.5)
        # 设置文本框的高度
        text_height = Cm(3)
        # 设置文本框的宽度
        text_width = Cm(30)

        # 获取当前主题和保存名称对应的聊天文本
        chat = chats[theme][save_name]
        # 去除聊天文本中的空格
        chat = chat.replace(' ','')
        # 重新设置文本框的顶部位置
        text_top = Cm(2)

        if first_text:
            # 若不是第一段文本，遍历聊天文本按换行符分割后的每一行
            for text in chat.split('\n'):
                # 提取文本中特定格式的内容添加到标题中
                if len(text) > 0:
                    header = header + ',' + get_content_in_minus(text)
                    # 在现有文本框中添加新段落
                    p = text_frame.add_paragraph()
                    # 设置段落的字体属性
                    set_font_properties(p, '宋体', Pt(16), RGBColor(0, 0, 0))
                    # 去除文本中特定格式的内容并设置为段落文本
                
                    p.text = remove_minus(text)
                    print('first text', text, len(text))
                    # 设置段落级别为 0
                    p.level = 0
                    # 设置段落的字符间距
                    p._pPr.get_or_add_defRPr().set(qn('w:kerning'), '50')
        else:
            # 若为第一段文本，在幻灯片上添加一个新的文本框
            text_box = slide.shapes.add_textbox(left=text_left, top=text_top, height=text_height, width=text_width)
            # 获取文本框的文本框架
            text_frame = text_box.text_frame
            # 允许文本框内的文本自动换行
            text_frame.word_wrap = True

            # 遍历聊天文本按换行符分割后的每一行
            for text in chat.split('\n'):
                if len(text) > 0:
                # 在文本框中添加新段落
                    p = text_frame.add_paragraph()
                    # 提取文本中特定格式的内容作为标题
                    header = get_content_in_minus(text)
                    # 设置段落的字体属性
                    set_font_properties(p, '宋体', Pt(16), RGBColor(0, 0, 0))
                    # 去除文本中特定格式的内容并设置为段落文本

                    print('>> text', text, len(text))
                    p.text = remove_minus(text)
                    # 设置段落级别为 0
                    p.level = 0

        # 标记已经添加过图片
        first_img = True
        # 标记已经添加过文本
        first_text = True

        # 若标题添加次数小于 2
        if header_text != 2:
            # 在幻灯片上添加一个标题文本框
            header_box = slide.shapes.add_textbox(left=Cm(0.8), top=Cm(0), height=Cm(1.8), width=Cm(30))
            # 获取标题文本框的文本框架
            header_frame = header_box.text_frame
            # 允许标题文本框内的文本自动换行
            header_frame.word_wrap = True
            # 在标题文本框中添加新段落
            header_para = header_frame.add_paragraph()
            # 设置标题段落的字体大小为 24 磅
            header_para.font.size = Pt(24)
            # 遍历文本框内所有段落
            for paragraph in header_frame.paragraphs:
                # 遍历段落内的所有运行对象
                for run in paragraph.runs:
                    # 设置运行对象的字体为黑体
                    run.font.name = '黑体'
            # 设置标题段落的文本
            header_para.text = f"{header}"
            # 标题添加次数加 1
            header_text = header_text + 1

# 设置生成的 PPT 文件的输出路径
output_filename = "../输出20251130.pptx"
# 保存演示文稿到指定路径
prs.save(output_filename)
# 打印提示信息，告知 PPT 已生成
print(f" PPT 已生成：{output_filename}")
